﻿namespace OasisCiq.Xml
{
    using System;
    using System.Collections.Generic;
    using System.Xml;
    using CommonTypes;
    using Xprl;
    using XS;

    // ReSharper disable MemberCanBePrivate.Global

    public class XprlXmlReader
    {
        private const string XmlNS = XmlNamespaces.PartyRelationships;
        private readonly XmlReader reader;
        private readonly CommonTypesXmlReader ctReader = new CommonTypesXmlReader();
        private readonly XpilXmlReader xpilReader;

        public XprlXmlReader(XmlReader reader)
        {
            this.reader = reader;
            xpilReader = new XpilXmlReader(reader);
        }

        public Relationship ReadRelationship()
        {
            if (!CheckElement("Relationship"))
            {
                return null;
            }

            var attrs = _XmlAttribute.GetAttributes(reader);
            var element = new Relationship();
            attrs = ReadRelationshipAttributes(element, attrs);
            attrs = ctReader.ReadDataQualityGroup(element, attrs);
            attrs = ctReader.ReadLanguageCodeGroup(element, attrs);
            ctReader.ReadExtendedAttributes(element, attrs);
            reader.Read(); // to r:Party node
            element.Party = ReadParty();
            reader.Read(); // from r:Relationship end element to next node
            return element;
        }

        public PartyType ReadParty()
        {
            var element = new PartyType();
            return ReadParty(element, "Party", XmlNS) ? element : null;
        }

        public bool ReadParty(PartyType element, string elementName, string elementNamespace)
        {
            if (element == null)
            {
                throw new ArgumentNullException("element");
            }

            if (!CheckElement(elementName, elementNamespace))
            {
                return false;
            }

            element = (PartyType)xpilReader.ReadPartyStartElement(element, elementName, elementNamespace);
            xpilReader.ReadPartyChildren(element);
            var relationship = ReadRelationship();
            while (relationship != null)
            {
                if (element.AdvancedRelationships == null)
                {
                    element.AdvancedRelationships = new List<Relationship>();
                }

                element.AdvancedRelationships.Add(relationship);
                relationship = ReadRelationship();
            }

            xpilReader.ReadPartyEndElement(element);
            return true;
        }

        public IEnumerable<_XmlAttribute> ReadRelationshipAttributes(
            Relationship element,
            IEnumerable<_XmlAttribute> attributes)
        {
            foreach (var xmlAttribute in attributes)
            {
                if (xmlAttribute.NS == XmlNS)
                {
                    switch (xmlAttribute.Name)
                    {
                        case "RelationshipID":
                            element.RelationshipId = new CTString(xmlAttribute.Value);
                            continue;
                        case "RelationshipIDType":
                            element.RelationshipIdType = new RelationshipIdTypeList(xmlAttribute.Value);
                            continue;
                        case "ID":
                            element.Id = new CTString(xmlAttribute.Value);
                            continue;
                        case "RelationshipType":
                            element.RelationshipType = new RelationshipTypeList(xmlAttribute.Value);
                            continue;
                        case "RelationshipCategory":
                            element.RelationshipCategory = new RelationshipCategoryList(xmlAttribute.Value);
                            continue;
                        case "RelationshipStatus":
                            element.RelationshipStatus = new RelationshipStatusList(xmlAttribute.Value);
                            continue;
                        case "RelationshipStartDateTime":
                            element.RelationshipStartDateTime = new XSDateTime(xmlAttribute.Value);
                            continue;
                        case "RelationshipEndDateTime":
                            element.RelationshipEndDateTime = new XSDateTime(xmlAttribute.Value);
                            continue;
                        case "RelationshipStartReason":
                            element.RelationshipStartReason = new RelationshipStartReasonList(xmlAttribute.Value);
                            continue;
                        case "RelationshipEndReason":
                            element.RelationshipEndReason = new RelationshipEndReasonList(xmlAttribute.Value);
                            continue;
                        case "RelationshipRelativityWithOtherParty":
                            element.RelationshipRelativityWithOtherParty = 
                                new RelationshipRelativityList(xmlAttribute.Value);
                            continue;
                        case "RelationshipRole":
                            element.RelationshipRole = new RelationshipRoleList(xmlAttribute.Value);
                            continue;
                        case "OtherPartyRelationshipRole":
                            element.OtherPartyRelationshipRole = new OtherPartyRelationshipRoleList(xmlAttribute.Value);
                            continue;
                        case "RelationshipPriority":
                            element.RelationshipPriority = new RelationshipPriorityList(xmlAttribute.Value);
                            continue;
                    }
                }

                yield return xmlAttribute;
            }
        }

        public bool CheckElement(string name)
        {
            return CheckElement(name, XmlNS);
        }

        public bool CheckElement(string name, string @namespace)
        {
            var ns = reader.NamespaceURI;
            var elem = reader.NodeType == XmlNodeType.Element ? reader.LocalName : null;
            return elem != null && ns == @namespace && elem == name;
        }
    }

    // ReSharper enable MemberCanBePrivate.Global
}
